using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using TXLooker.Common.Core;
using TXLooker.Common.UI;
using TXLooker.WorkItemExtention.Core;

namespace TXLooker.WorkItemExtention.UI
{

    /// <summary>
    /// This control is tree map of the TFS list
    /// </summary>
    internal partial class TFSTreeCtrlServerProject : UserControl
    {
        #region Internal Class Fields

        private Dictionary<Guid, TreeNode> m_itemsTreeMAP = new Dictionary<Guid, TreeNode>();

        #endregion Internal Class Fields

        #region Class Properties

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public WIObject SelectedObject
        {
            get { return this.m_selObject; }
            set
            {
                if (this.m_selObject == value) return;
                this.m_selObject = value;
                this.RaiseSelectionChanged();
            }
        }

        private WIObject m_selObject = null;

        #region event SelectionChanged

        public event EventHandler SelectionChanged;

        private void RaiseSelectionChanged()
        {
            if (this.SelectionChanged != null)
                this.SelectionChanged(this, EventArgs.Empty);
        }

        #endregion event SelectionChanged

        #endregion Class Properties

        #region Class Constructors

        public TFSTreeCtrlServerProject()
        {
            InitializeComponent();
            this.m_tvTFSMap.AfterSelect += new TreeViewEventHandler(OnAfterNodeSelect);
        }

        #endregion Class Constructors

        public void LoadF()
        {
            MethodInvoker invoker = delegate { LoadTree(); };
            if (this.InvokeRequired)
                this.Invoke(invoker);
            else invoker();
        }

        public void LoadTree()
        {
            try
            {
                this.m_tvTFSMap.BeginUpdate();
                this.m_tvTFSMap.Nodes.Clear();

                IEnumerable<TreeNode> nodes = null;

                lock (this.m_itemsTreeMAP)
                {
                    this.m_itemsTreeMAP.Clear();

                    List<WIObject> list = new List<WIObject>();

                    WIObjectsStore.NewServers += new TFEventHandler<IEnumerable<WIServerProvider>>(OnNewChildItems<WIServerProvider>);
                    WIObjectsStore.PreRemoveServers += new TFEventHandler<IEnumerable<WIServerProvider>>(OnPreRemoveChildItems<WIServerProvider>);

                    foreach (WIObject item in WIObjectsStore.Servers)
                        list.Add(item);

                    nodes = this.InitNodes<WIObject>(list);
                }

                foreach (TreeNode node in nodes)
                    this.m_tvTFSMap.Nodes.Add(node);
                this.m_tvTFSMap.Sort();
            }
            finally
            {
                this.m_tvTFSMap.EndUpdate();
            }
        }

        private IEnumerable<TreeNode> InitNodes<T>(IEnumerable<T> items) where T : WIObject
        {
            List<TreeNode> nodes = new List<TreeNode>();

            lock (this.m_itemsTreeMAP)
            {
                foreach (T item in items)
                {
                    item.NewChildItems += new TFEventHandler<IEnumerable<WIObject>>(OnNewChildItems);
                    item.PreRemoveChildItems += new TFEventHandler<IEnumerable<WIObject>>(OnPreRemoveChildItems);

                    TreeNode node = new TreeNode(item.FolderName);
                    InitImage<T>(item, node);
                    node.Tag = new TreeNodeTag<WIObjectType>(item.Type, item);
                    if (item.Type != WIObjectType.QueriesRoot && item.Type != WIObjectType.QueriesGroup && item.Type != WIObjectType.Query && item.Type != WIObjectType.Project)
                    {
                        foreach (TreeNode child in InitNodes(item.ChildItems))
                            node.Nodes.Add(child);
                    }

                    this.m_itemsTreeMAP.Add(item.ID, node);

                    nodes.Add(node);
                }
            }

            return nodes;
        }

        private static void InitImage<T>(T item, TreeNode node) where T : WIObject
        {
            switch ((item as WIObject).Type)
            {
                case WIObjectType.Server:
                    node.ImageIndex = 0;
                    break;
                case WIObjectType.Project:
                    node.ImageIndex = 1;
                    break;
                default: break;
            }
        }

        private void OnNewChildItems<T>(object sender, IEnumerable<T> items) where T : WIObject
        {
            MethodInvoker invoker = delegate { this.InitItems(items); };

            if (this.InvokeRequired) this.Invoke(invoker);
            else invoker();
        }
        private void InitItems<T>(IEnumerable<T> items) where T : WIObject
        {
            try
            {
                this.m_tvTFSMap.BeginUpdate();

                List<T> list = new List<T>(items);

                if (list.Count != 0)
                {
                    lock (this.m_itemsTreeMAP)
                    {
                        TreeNode parent = this.m_itemsTreeMAP[list[0].ID].Parent;

                        TreeNodeCollection collection = parent == null ? this.m_tvTFSMap.Nodes : parent.Nodes;

                        foreach (TreeNode node in this.InitNodes(items))
                            collection.Add(node);
                    }
                }
            }
            finally
            {
                this.m_tvTFSMap.EndUpdate();
            }
        }

        private void OnPreRemoveChildItems<T>(object sender, IEnumerable<T> items) where T : WIObject
        {
            MethodInvoker invoker = delegate { this.RemoveItems(items); };

            if (this.InvokeRequired) this.Invoke(invoker);
            else invoker();

        }
        private void RemoveItems<T>(IEnumerable<T> items) where T : WIObject
        {
            try
            {
                this.m_tvTFSMap.BeginUpdate();

                lock (this.m_itemsTreeMAP)
                {
                    foreach (T item in items)
                    {
                        TreeNode node = this.m_itemsTreeMAP[item.ID];
                        this.RemoveNodes(item.ChildItems);
                        node.Remove();
                    }
                }
            }
            finally
            {
                this.m_tvTFSMap.EndUpdate();
            }
        }
        private void RemoveNodes<T>(IEnumerable<T> items) where T : WIObject
        {
            lock (this.m_itemsTreeMAP)
            {
                foreach (T item in items)
                {
                    TreeNode node = this.m_itemsTreeMAP[item.ID];
                    this.RemoveNodes(item.ChildItems);
                    node.Remove();
                }
            }
        }

        public TreeView TreeView
        {
            get { return this.m_tvTFSMap; }
        }

        private void OnAfterNodeSelect(object sender, TreeViewEventArgs args)
        {
            TreeNodeTag<WIObjectType> sel = (args.Node.Tag as TreeNodeTag<WIObjectType>);
            this.SelectedObject = sel.Tag as WIObject;
            switch (SelectedObject.Type)
            {
                case WIObjectType.Server:
                    this.TreeView.SelectedNode.SelectedImageIndex = 0;
                    break;
                case WIObjectType.Project:
                    this.TreeView.SelectedNode.SelectedImageIndex = 1;
                    break;
                default: break;    
            }
        }
    }
}
